package com.smart.community.commons.websocket.security;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket安全验证管理器
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Component
@Slf4j
public class WebSocketSecurityManager {

    // 黑名单IP集合
    private final Set<String> blacklistIps = ConcurrentHashMap.newKeySet();
    
    // 白名单IP集合
    private final Set<String> whitelistIps = ConcurrentHashMap.newKeySet();

    /**
     * 验证用户连接权限
     * 
     * @param userId 用户ID
     * @param username 用户名
     * @param userType 用户类型
     * @param propertyCompanyId 物业公司ID
     * @param clientIp 客户端IP
     * @return 验证结果
     */
    public SecurityValidationResult validateConnection(Long userId, String username, String userType, 
                                                     Long propertyCompanyId, String clientIp) {
        SecurityValidationResult result = new SecurityValidationResult();
        result.setUserId(userId);
        result.setUsername(username);
        result.setClientIp(clientIp);
        result.setTimestamp(LocalDateTime.now());

        try {
            // 1. 检查IP黑名单
            if (isIpBlacklisted(clientIp)) {
                result.setValid(false);
                result.setReason("IP地址在黑名单中");
                log.warn("IP地址在黑名单中，拒绝连接，IP: {}, 用户ID: {}", clientIp, userId);
                return result;
            }

            // 2. 检查IP白名单（如果启用）
            if (!whitelistIps.isEmpty() && !isIpWhitelisted(clientIp)) {
                result.setValid(false);
                result.setReason("IP地址不在白名单中");
                log.warn("IP地址不在白名单中，拒绝连接，IP: {}, 用户ID: {}", clientIp, userId);
                return result;
            }

            // 3. 检查用户权限
            if (!validateUserPermissions(userId, userType, propertyCompanyId)) {
                result.setValid(false);
                result.setReason("用户权限不足");
                log.warn("用户权限不足，拒绝连接，用户ID: {}, 用户类型: {}", userId, userType);
                return result;
            }

            result.setValid(true);
            result.setReason("验证通过");
            log.info("WebSocket连接验证通过，用户ID: {}, 用户名: {}, IP: {}", userId, username, clientIp);

        } catch (Exception e) {
            log.error("WebSocket连接验证异常，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            result.setValid(false);
            result.setReason("验证过程发生异常: " + e.getMessage());
        }

        return result;
    }

    /**
     * 验证消息权限
     * 
     * @param userId 用户ID
     * @param messageType 消息类型
     * @param targetRoom 目标房间
     * @return 验证结果
     */
    public SecurityValidationResult validateMessage(Long userId, String messageType, String targetRoom) {
        SecurityValidationResult result = new SecurityValidationResult();
        result.setUserId(userId);
        result.setMessageType(messageType);
        result.setTargetRoom(targetRoom);
        result.setTimestamp(LocalDateTime.now());

        try {
            // 1. 检查用户权限
            if (!validateUserPermissions(userId, null, null)) {
                result.setValid(false);
                result.setReason("用户权限信息不存在");
                return result;
            }

            // 2. 检查消息类型权限
            if (!canSendMessageType(userId, messageType)) {
                result.setValid(false);
                result.setReason("无权限发送该类型消息");
                log.warn("用户无权限发送消息类型，用户ID: {}, 消息类型: {}", userId, messageType);
                return result;
            }

            // 3. 检查房间权限（如果指定了房间）
            if (targetRoom != null && !canAccessRoom(userId, targetRoom)) {
                result.setValid(false);
                result.setReason("无权限访问该房间");
                log.warn("用户无权限访问房间，用户ID: {}, 房间ID: {}", userId, targetRoom);
                return result;
            }

            result.setValid(true);
            result.setReason("消息验证通过");

        } catch (Exception e) {
            log.error("消息权限验证异常，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            result.setValid(false);
            result.setReason("验证过程发生异常: " + e.getMessage());
        }

        return result;
    }

    /**
     * 添加IP到黑名单
     * 
     * @param ip IP地址
     * @param reason 原因
     */
    public void addToBlacklist(String ip, String reason) {
        blacklistIps.add(ip);
        log.info("IP已添加到黑名单，IP: {}, 原因: {}", ip, reason);
    }

    /**
     * 从黑名单移除IP
     * 
     * @param ip IP地址
     */
    public void removeFromBlacklist(String ip) {
        blacklistIps.remove(ip);
        log.info("IP已从黑名单移除，IP: {}", ip);
    }

    /**
     * 添加IP到白名单
     * 
     * @param ip IP地址
     */
    public void addToWhitelist(String ip) {
        whitelistIps.add(ip);
        log.info("IP已添加到白名单，IP: {}", ip);
    }

    /**
     * 从白名单移除IP
     * 
     * @param ip IP地址
     */
    public void removeFromWhitelist(String ip) {
        whitelistIps.remove(ip);
        log.info("IP已从白名单移除，IP: {}", ip);
    }

    /**
     * 检查IP是否在黑名单中
     */
    private boolean isIpBlacklisted(String ip) {
        return blacklistIps.contains(ip);
    }

    /**
     * 检查IP是否在白名单中
     */
    private boolean isIpWhitelisted(String ip) {
        return whitelistIps.contains(ip);
    }

    /**
     * 验证用户权限
     */
    private boolean validateUserPermissions(Long userId, String userType, Long propertyCompanyId) {
        // 这里应该根据实际的权限系统进行验证
        // 暂时返回true，实际项目中需要集成权限系统
        return userId != null && userId > 0;
    }

    /**
     * 检查用户是否可以发送指定类型的消息
     */
    private boolean canSendMessageType(Long userId, String messageType) {
        // 这里应该根据实际的权限系统进行验证
        // 暂时返回true，实际项目中需要集成权限系统
        return true;
    }

    /**
     * 检查用户是否可以访问指定房间
     */
    private boolean canAccessRoom(Long userId, String roomId) {
        // 这里应该根据实际的权限系统进行验证
        // 暂时返回true，实际项目中需要集成权限系统
        return true;
    }

    /**
     * 安全验证结果
     */
    @Data
    public static class SecurityValidationResult {
        private Long userId;
        private String username;
        private String clientIp;
        private String messageType;
        private String targetRoom;
        private boolean valid;
        private String reason;
        private LocalDateTime timestamp;
    }
}
